﻿// -------------------------------------------------------------------------
//    @FileName         :    NFCityNpc.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-09-28
//    @Email			:    445267987@qq.com
//    @Module           :    NFCityNpc
//    @Desc             :
//
// -------------------------------------------------------------------------

#include "NFCityNpc.h"

#include "NFCityNpcUtil.h"
#include "NFCityPlayer.h"
#include "DescStore/FunctionNpcDesc.h"
#include "DescStore/TriggerNpcDesc.h"

NFCityNpc::NFCityNpc()
{
    if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
    {
        CreateInit();
    }
    else
    {
        ResumeInit();
    }
}

NFCityNpc::~NFCityNpc()
{
}

int NFCityNpc::CreateInit()
{
    SetObjectType(EN_CITY_WOT_NPC);
    m_iNpcId = INVALID_ID;
    m_iSpawnId = INVALID_ID;
    m_iLocationId = 0;
    m_iNpcGroupId = 0;

    m_iLastTickTime = NF_ADJUST_TIMENOW();
    m_iLeftTime = INVALID_ID;
    m_bIsHide = false;

    m_iEndTime = 0;

    m_bIsRemove = false;

    m_eCamp = EN_GUILD_CAMP_TYPE_NONE;

    SetTimer(1000, 0, 0, 0, 0, 0);
    return 0;
}

int NFCityNpc::ResumeInit()
{
    return 0;
}

int NFCityNpc::Init(int iNpcID, int iLeftTime)
{
    auto pNpcDesc = FunctionNpcDesc::Instance()->GetDesc(iNpcID);
    CHECK_NULL_WF(iNpcID, pNpcDesc, "invalid npc id:{}", iNpcID);

    m_iNpcId = iNpcID;
    m_iLeftTime = iLeftTime > 0 ? iLeftTime : INVALID_ID;
    m_iLastTickTime = NF_ADJUST_TIMENOW();

    for (int i = 0; i < pNpcDesc->function.size(); ++i)
    {
        InitNpcType(pNpcDesc->function[i].type, pNpcDesc->function[i].id);
    }

    m_oLevelExt.Init(this);
    return 0;
}

int NFCityNpc::InitNpcType(int iType, int iId)
{
    switch (iType)
    {
        case proto_ff::EN_FUNCTION_NPC_TYPE_TRIGGER_BATTLE:
        case proto_ff::EN_FUNCTION_NPC_TYPE_AIR_WALL:
            InitTriggerLevelNpc(iId);
            break;

        default:
            break;
    }

    return 0;
}

int NFCityNpc::InitTriggerLevelNpc(int iId)
{
    auto pTriggerNpcDesc = TriggerNpcDesc::Instance()->GetDesc(iId);
    CHECK_NULL(iId, pTriggerNpcDesc);

    m_bIsHide = pTriggerNpcDesc->is_hide ? true : false;
    m_iLeftTime = pTriggerNpcDesc->duration > 0 ? pTriggerNpcDesc->duration : INVALID_ID;

    return 0;
}

int NFCityNpc::OnTimer(int timeId, int callCount)
{
    TickSec();
    return 0;
}

int NFCityNpc::TickSec()
{
    if (IsNeedRemove())
    {
        NFCityNpcUtil::RemoveNpc(this);
    }

    m_iLastTickTime = NF_ADJUST_TIMENOW();
    return 0;
}

void NFCityNpc::SetSpawnId(int iSpawnId, int iLocationId, int iSpawnEndTime)
{
    m_iSpawnId = iSpawnId;
    m_iLocationId = iLocationId;
    m_iEndTime = iSpawnEndTime;
}

bool NFCityNpc::IsNeedRemove()
{
    if (m_bIsRemove)
    {
        return true;
    }

    if (m_iLeftTime > 0)
    {
        int iGap = NF_ADJUST_TIMENOW() - m_iLastTickTime;
        m_iLeftTime -= iGap;
        m_iLeftTime = std::max(0, m_iLeftTime);

        return m_iLeftTime == 0;
    }

    if (m_iEndTime > 0 && NF_ADJUST_TIMENOW() >= m_iEndTime)
    {
        return true;
    }

    return false;
}

int NFCityNpc::Refresh(int iLeftTime)
{
    auto pNpcDesc = FunctionNpcDesc::Instance()->GetDesc(m_iNpcId);
    CHECK_NULL_WF(0, pNpcDesc, "invalid npc id:{}", m_iNpcId);

    m_iLeftTime = iLeftTime > 0 ? iLeftTime : INVALID_ID;
    m_iLastTickTime = NF_ADJUST_TIMENOW();

    for (int i = 0; i < pNpcDesc->function.size(); ++i)
    {
        InitNpcType(pNpcDesc->function[i].type, pNpcDesc->function[i].id);
    }

    m_oLevelExt.Init(this);
    return 0;
}

int NFCityNpc::SynNpcInfo(const proto_ff::CityNpcInfo& rInfo)
{
    if(rInfo.has_guild_battle_info())
    {
        SetNpcCamp((enGuildCampType)rInfo.guild_battle_info().camp());
    }

    return 0;
}

bool NFCityNpc::IsVisibleByLevel(int iLevel)
{
    auto pNpcDesc = FunctionNpcDesc::Instance()->GetDesc(m_iNpcId);
    if( pNpcDesc && pNpcDesc->visual_level <= iLevel )
    {
        return true;
    }

    return false;
}

bool NFCityNpc::IsVisibleByQuest(int iQuestId)
{
    auto pNpcDesc = FunctionNpcDesc::Instance()->GetDesc(m_iNpcId);
    CHECK_NULL_RE_FALSE_WF(0, pNpcDesc, "invalid npc id:{}", m_iNpcId);

    if (pNpcDesc->function.size() <= 0)
    {
        return false;
    }

    if (pNpcDesc->function[0].type != proto_ff::EN_FUNCTION_NPC_TYPE_TASK)
        return false;

    if (!m_bIsHide)
    {
        return true;
    }
    else
    {
        return m_oLevelExt.IsVisibleByQuest(iQuestId);
    }

    return false;
}

bool NFCityNpc::IsVisible(NFCityWorldObject* pAcceptWO)
{
    if (!m_bIsHide)
    {
        if (pAcceptWO->IsPlayer())
        {
            NFCityPlayer* pPlayer = dynamic_cast<NFCityPlayer*>(pAcceptWO);
            CHECK_NULL_RE_FALSE(0, pPlayer);
            if (pPlayer->GetBattleExt()->IsTroupeHide(GetGlobalId()))
            {
                return false;
            }

            auto pNpcDesc = FunctionNpcDesc::Instance()->GetDesc(m_iNpcId);
            if (pNpcDesc && pPlayer->GetLevel() < pNpcDesc->visual_level)
            {
                return false;
            }
        }

        return true;
    }
    else
    {
        return m_oLevelExt.IsHideVisible(pAcceptWO);
    }

    return false;
}
